package com.qboot.quartz.service.impl;

import cn.hutool.core.comparator.CompareUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONException;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.qboot.common.consts.MsgConst;
import com.qboot.common.consts.NumberConst;
import com.qboot.common.entity.Result;
import com.qboot.common.exception.QuartzException;
import com.qboot.common.utils.AssertUtils;
import com.qboot.common.utils.SpringUtils;
import com.qboot.quartz.entity.JobInfo;
import com.qboot.quartz.mapper.JobInfoMapper;
import com.qboot.quartz.service.JobInfoService;
import com.qboot.quartz.service.QuartzService;
import com.qboot.quartz.vo.JobInfoVo;
import lombok.RequiredArgsConstructor;
import org.apache.commons.lang3.StringUtils;
import org.quartz.CronExpression;
import org.springframework.beans.factory.NoSuchBeanDefinitionException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.quartz.QuartzJobBean;
import org.springframework.stereotype.Service;
import org.springframework.util.ObjectUtils;

import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * 定时任务 接口实现类
 *
 * @author Tellsea
 * @date 2023-02-28
 */
@Service
@RequiredArgsConstructor(onConstructor_ = @Autowired)
public class JobInfoServiceImpl extends ServiceImpl<JobInfoMapper, JobInfo> implements JobInfoService {

    private final QuartzService quartzService;

    @Override
    public Page<JobInfoVo> queryList(Page page, JobInfoVo entity) {
        return this.baseMapper.queryList(page, entity);
    }

    @Override
    public JobInfoVo queryById(Long id) {
        return this.baseMapper.queryById(id);
    }

    @Override
    public Result saveEntity(JobInfoVo entity) {
        try {
            Long count = this.baseMapper.selectCount(new LambdaQueryWrapper<JobInfo>()
                    .eq(JobInfo::getJobName, entity.getJobName()));
            AssertUtils.isTrue(CompareUtil.compare(count, 0L) > 0, entity.getJobName() + " 已经存在");
            Object bean = SpringUtils.getBean(entity.getJobName());
            AssertUtils.isEmpty(ObjectUtils.isEmpty(bean), "Bean 不存在");
            AssertUtils.isTrue(!CronExpression.isValidExpression(entity.getCron()), "cron 表达式错误");
            Map params = new HashMap(16);
            if (StringUtils.isNotEmpty(entity.getParams())) {
                params = JSON.parseObject(entity.getParams(), Map.class);
            }
            this.baseMapper.insert(entity);
            quartzService.addJob((Class<? extends QuartzJobBean>) bean.getClass(), entity.getJobName(), entity.getJobGroup(), entity.getCron(), params);
            if (CompareUtil.compare(entity.getIsEnable(), Long.valueOf(NumberConst.TWO)) == 0) {
                quartzService.pauseJob(entity.getJobName(), entity.getJobGroup());
            }
            return Result.ok(MsgConst.SAVE_SUCCESS);
        } catch (NoSuchBeanDefinitionException e) {
            throw new QuartzException("Bean 不存在");
        } catch (JSONException e) {
            throw new QuartzException("参数格式解析异常");
        }
    }

    @Override
    public Result updateEntityById(JobInfoVo entity) {
        try {
            List<JobInfo> countList = this.baseMapper.selectList(new LambdaQueryWrapper<JobInfo>()
                    .eq(JobInfo::getJobName, entity.getJobName()));
            AssertUtils.isTrue(countList.size() > 1, entity.getJobName() + " 存在多个");
            AssertUtils.isTrue(CompareUtil.compare(countList.size(), 1) == 0
                    && CompareUtil.compare(countList.get(0).getId(), entity.getId()) != 0, entity.getJobName() + " 已经存在");
            Object bean = SpringUtils.getBean(entity.getJobName());
            AssertUtils.isEmpty(ObjectUtils.isEmpty(bean), "Bean 不存在");
            AssertUtils.isTrue(!CronExpression.isValidExpression(entity.getCron()), "cron 表达式错误");
            Map params = new HashMap(16);
            if (StringUtils.isNotEmpty(entity.getParams())) {
                params = JSON.parseObject(entity.getParams(), Map.class);
            }
            JobInfo oldJobInfo = this.baseMapper.selectById(entity.getId());
            quartzService.deleteJob(oldJobInfo.getJobName(), oldJobInfo.getJobGroup());
            quartzService.addJob((Class<? extends QuartzJobBean>) bean.getClass(), entity.getJobName(), entity.getJobGroup(), entity.getCron(), params);
            if (CompareUtil.compare(entity.getIsEnable(), Long.valueOf(NumberConst.TWO)) == 0) {
                quartzService.pauseJob(entity.getJobName(), entity.getJobGroup());
            }
            this.baseMapper.updateById(entity);
            return Result.ok(MsgConst.UPDATE_SUCCESS);
        } catch (NoSuchBeanDefinitionException e) {
            throw new QuartzException("Bean 不存在");
        } catch (JSONException e) {
            throw new QuartzException("参数格式解析异常");
        }
    }

    @Override
    public Result removeEntityById(Long id) {
        JobInfo entity = this.baseMapper.selectById(id);
        quartzService.deleteJob(entity.getJobName(), entity.getJobGroup());
        this.baseMapper.deleteById(id);
        return Result.ok(MsgConst.REMOVE_SUCCESS);
    }

    @Override
    public Result removeBatchEntityByIds(List<Long> ids) {
        for (Long id : ids) {
            JobInfo entity = this.baseMapper.selectById(id);
            quartzService.deleteJob(entity.getJobName(), entity.getJobGroup());
            this.baseMapper.deleteById(id);
        }
        return Result.ok(MsgConst.REMOVE_SUCCESS);
    }
}
